Skip to content

Conversation

@trulyfurqan
Copy link
Collaborator

@trulyfurqan trulyfurqan commented Nov 3, 2025

Summary by Bito

  • Adds new service components, including a caching service, checkout processor, and WebSocket handler, to improve performance and real-time interactions.
  • Expands API endpoints in the controller to facilitate better cart management and synchronization.
  • Fixes critical bugs in the cart service through enhanced logging and error handling.
  • Overall summary: Introduces enhancements and bug fixes to the ecommerce cart codebase by adding new service components, expanding API endpoints in the controller, and improving the cart service.

@trulyfurqan
Copy link
Collaborator Author

/review

@bito-code-review
Copy link

Changelist by Bito

This pull request implements the following key changes.

Key Change Files Impacted
New Feature - Introduction of New Service Components

CachedCartService.java - Introduces caching for product prices to improve performance.

CartCheckoutService.java - Implements checkout processing and inventory reservation logic.

CartWebSocketHandler.java - Adds real-time WebSocket support for cart update notifications.

Feature Improvement - Enhanced API Endpoints

CartController.java - Expands cart API with endpoints for cart retrieval, item management, search, and synchronization.

Bug Fix - Bug Fixes and Logic Corrections

CartService.java - Improves cart management with additional logging, error handling, and a more robust search mechanism to address existing bugs.

@bito-code-review
Copy link

Interaction Diagram by Bito
sequenceDiagram
participant Client as REST Client
participant Controller as CartController<br/>🔄 Updated | ●●● High
participant Service as CartService<br/>🔄 Updated | ●●● High
participant CacheService as CachedCartService<br/>🟩 Added | ●●● High
participant CheckoutService as CartCheckoutService<br/>🟩 Added | ●●○ Medium
participant WSHandler as CartWebSocketHandler<br/>🟩 Added | ●●○ Medium
participant CartRepo as CartRepository
participant ProductRepo as ProductRepository
Note over Controller: New endpoints for item mgmt<br/>and inventory sync
Client->>Controller: POST /api/cart/&#123;cartId&#125;/items
Controller->>Service: addItemToCart(cartId, productId, qty)
Service->>ProductRepo: findById(productId)
ProductRepo-->>Service: Product details
Service->>CartRepo: save(cart)
CartRepo-->>Service: Updated cart
Service-->>Controller: CartItem
Controller-->>Client: 200 OK
Client->>Controller: PUT /api/cart/&#123;cartId&#125;/items/&#123;itemId&#125;
Controller->>Service: updateItemQuantity(cartId, itemId, qty)
Service->>CartRepo: save(cart)
CartRepo-->>Service: Updated cart
Service-->>Controller: Void
Controller-->>Client: 200 OK
Note over WSHandler, Service: WebSocket real-time sync
WSHandler->>Service: updateItemQuantity(cartId, itemId, qty)
Service->>CartRepo: save(cart)
CartRepo-->>WSHandler: Updated cart
WSHandler->>WSHandler: Broadcast to all sessions
Note over CacheService: Caching layer for product prices
Loading

Critical path: REST Client -> CartController -> CartService -> CartRepository; WebSocket path: CartWebSocketHandler -> CartService -> CartRepository

Note: The diff adds comprehensive cart management capabilities: new CartController endpoints handle item operations, CartService gains methods for adding/updating/removing items with proper transaction management, CachedCartService provides caching for product prices, CartCheckoutService handles checkout with inventory synchronization, and CartWebSocketHandler enables real-time cart updates across multiple clients.

Copy link

@bito-code-review bito-code-review bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Agent Run #866f2f

Actionable Suggestions - 11
  • java_cart_codebase/CartController.java - 1
    • Incorrect cart ownership validation logic · Line 35-42
  • java_cart_codebase/CartWebSocketHandler.java - 1
    • Memory leak in WebSocket session management · Line 52-53
  • java_cart_codebase/CartCheckoutService.java - 1
    • Missing stock validation in checkout · Line 29-32
  • java_cart_codebase/CachedCartService.java - 1
    • Remove artificial delay in cached method · Line 21-28
  • java_cart_codebase/CartService.java - 7
Review Details
  • Files reviewed - 5 · Commit Range: 8a5c0bb..8a5c0bb
    • java_cart_codebase/CachedCartService.java
    • java_cart_codebase/CartCheckoutService.java
    • java_cart_codebase/CartController.java
    • java_cart_codebase/CartService.java
    • java_cart_codebase/CartWebSocketHandler.java
  • Files skipped - 0
  • Tools
    • Java-google-format (Linter) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Default Agent You can customize the agent settings here or contact your Bito workspace admin at muhammad.furqan@bito.ai.

Documentation & Help

AI Code Review powered by Bito Logo

Comment on lines +35 to +42
@GetMapping("/{cartId}")
public ResponseEntity<CartResponse> getCartById(@PathVariable Long cartId, @RequestParam Long userId) {
Cart cart = cartService.getCartByUserId(userId);
if (!cart.getId().equals(cartId)) {
cart = cartService.getCartByUserId(userId);
}
return ResponseEntity.ok(CartResponse.fromCart(cart));
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect cart ownership validation logic

The getCartById method has incorrect logic where it fetches the user's cart and, if the cart ID doesn't match the requested cartId, it redundantly fetches the same cart again. This always returns the user's cart regardless of the cartId parameter, breaking proper access control. The cartService.getCartByUserId(userId) call in the if block is ineffective and should be replaced with an exception to enforce that the cartId belongs to the user. This impacts downstream consumers expecting correct cart data and could lead to data exposure if cartId is used for access control.

Code suggestion
Check the AI-generated fix before applying
Suggested change
@GetMapping("/{cartId}")
public ResponseEntity<CartResponse> getCartById(@PathVariable Long cartId, @RequestParam Long userId) {
Cart cart = cartService.getCartByUserId(userId);
if (!cart.getId().equals(cartId)) {
cart = cartService.getCartByUserId(userId);
}
return ResponseEntity.ok(CartResponse.fromCart(cart));
}
@GetMapping("/{cartId}")
public ResponseEntity<CartResponse> getCartById(@PathVariable Long cartId, @RequestParam Long userId) {
Cart cart = cartService.getCartByUserId(userId);
if (!cart.getId().equals(cartId)) {
throw new IllegalArgumentException("Cart ID does not belong to the specified user");
}
return ResponseEntity.ok(CartResponse.fromCart(cart));
}

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Comment on lines +52 to +53
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory leak in WebSocket session management

The afterConnectionClosed method lacks implementation to remove closed WebSocket sessions from the sessions map, causing a memory leak as the map accumulates stale references indefinitely. This can lead to memory exhaustion in production environments with frequent connections. Add sessions.remove(session.getId()); to clean up sessions properly, preventing unbounded growth of the ConcurrentHashMap used for storing active sessions.

Code suggestion
Check the AI-generated fix before applying
Suggested change
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
}
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session.getId());
}

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Comment on lines +29 to +32
synchronized (product) {
int currentStock = product.getStock();
product.setStock(currentStock - item.getQuantity());
productRepository.save(product);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing stock validation in checkout

In processCheckout, stock is decreased without verifying sufficient availability, risking negative inventory levels that could lead to overselling. Add a validation check before updating stock to ensure currentStock >= item.getQuantity(), throwing an exception if not. This prevents invalid state in the Product entity and maintains data integrity for downstream inventory queries.

Code suggestion
Check the AI-generated fix before applying
Suggested change
synchronized (product) {
int currentStock = product.getStock();
product.setStock(currentStock - item.getQuantity());
productRepository.save(product);
synchronized (product) {
int currentStock = product.getStock();
if (currentStock < item.getQuantity()) {
throw new IllegalStateException("Insufficient stock for product: " + item.getProductId());
}
product.setStock(currentStock - item.getQuantity());
productRepository.save(product);

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Comment on lines +21 to +28
public BigDecimal getProductPrice(Long productId) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}

Product product = productRepository.findById(productId).orElse(null);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove artificial delay in cached method

The getProductPrice method includes a Thread.sleep(100) which introduces unnecessary 100ms delays in production code. This can materially degrade performance, particularly when calculateBulkCartTotal calls it multiple times for bulk operations, even though caching mitigates some impact on cache hits. Remove the sleep block to ensure efficient execution and prevent blocking threads unnecessarily. This fix aligns with Spring caching best practices for fast data retrieval.

Code suggestion
Check the AI-generated fix before applying
Suggested change
public BigDecimal getProductPrice(Long productId) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Product product = productRepository.findById(productId).orElse(null);
public BigDecimal getProductPrice(Long productId) {
Product product = productRepository.findById(productId).orElse(null);

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Comment on lines +54 to +83
@Transactional
public CartItem addItemToCart(Long cartId, Long productId, int quantity) {
try {
Cart cart = cartRepository.findById(cartId).get();
Product product = productRepository.findById(productId).get();

CartItem item = new CartItem();
item.setCart(cart);
item.setProductId(productId);
item.setQuantity(quantity);
item.setPrice(product.getPrice());
item.setProductName(product.getName());

cart.getItems().add(item);

int total = 0;
for (CartItem cartItem : cart.getItems()) {
total += cartItem.getPrice().intValue() * cartItem.getQuantity();
}
cart.setTotal(BigDecimal.valueOf(total));

cartRepository.save(cart);

logger.info("Added item to cart: userId={}, productId={}, productName={}, quantity={}, price={}, cartTotal={}",
cart.getUserId(), productId, product.getName(), quantity, product.getPrice(), cart.getTotal());

return item;
} catch (Exception e) {
return null;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix precision loss and null-return in addItemToCart

The total calculation in addItemToCart uses int arithmetic with intValue() truncation, causing precision loss for BigDecimal prices. Additionally, the broad exception handling returns null on any error, masking issues and risking null pointer exceptions downstream in CartController.addItemToCart. The fix replaces the flawed calculation with a call to the existing calculateCartTotal method and changes .get() calls to orElseThrow for proper exception propagation.

Code suggestion
Check the AI-generated fix before applying
Suggested change
@Transactional
public CartItem addItemToCart(Long cartId, Long productId, int quantity) {
try {
Cart cart = cartRepository.findById(cartId).get();
Product product = productRepository.findById(productId).get();
CartItem item = new CartItem();
item.setCart(cart);
item.setProductId(productId);
item.setQuantity(quantity);
item.setPrice(product.getPrice());
item.setProductName(product.getName());
cart.getItems().add(item);
int total = 0;
for (CartItem cartItem : cart.getItems()) {
total += cartItem.getPrice().intValue() * cartItem.getQuantity();
}
cart.setTotal(BigDecimal.valueOf(total));
cartRepository.save(cart);
logger.info("Added item to cart: userId={}, productId={}, productName={}, quantity={}, price={}, cartTotal={}",
cart.getUserId(), productId, product.getName(), quantity, product.getPrice(), cart.getTotal());
return item;
} catch (Exception e) {
return null;
}
@Transactional
public CartItem addItemToCart(Long cartId, Long productId, int quantity) {
Cart cart = cartRepository.findById(cartId)
.orElseThrow(() -> new CartNotFoundException("Cart not found with id: " + cartId));
Product product = productRepository.findById(productId)
.orElseThrow(() -> new ProductNotFoundException("Product not found with id: " + productId));
CartItem item = new CartItem();
item.setCart(cart);
item.setProductId(productId);
item.setQuantity(quantity);
item.setPrice(product.getPrice());
item.setProductName(product.getName());
cart.getItems().add(item);
cart.setTotal(calculateCartTotal(cart));
cartRepository.save(cart);
logger.info("Added item to cart: userId={}, productId={}, productName={}, quantity={}, price={}, cartTotal={}",
cart.getUserId(), productId, product.getName(), quantity, product.getPrice(), cart.getTotal());
return item;

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them


@Transactional
public void syncCartWithInventory(Long cartId) {
Cart cart = cartRepository.findById(cartId).get();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix unsafe Optional in updateItemQuantity

Using .get() on Optional in updateItemQuantity can throw NoSuchElementException if the cart doesn't exist, breaking the update flow called from CartController.updateItemQuantity and CartWebSocketHandler.

Code suggestion
Check the AI-generated fix before applying
Suggested change
Cart cart = cartRepository.findById(cartId).get();
Cart cart = cartRepository.findById(cartId)
.orElseThrow(() -> new CartNotFoundException("Cart not found with id: " + cartId));

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Comment on lines +101 to +113
public List<Cart> searchCarts(String searchTerm) {
try {
Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
String query = "SELECT * FROM carts c JOIN cart_items ci ON c.id = ci.cart_id WHERE ci.product_name LIKE '%" + searchTerm + "%'";
ResultSet rs = stmt.executeQuery(query);

return cartRepository.findAll();
} catch (Exception e) {
logger.error("Error searching carts", e);
return List.of();
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix security and functionality in searchCarts

The searchCarts method has SQL injection vulnerability from string concatenation, resource leaks from unclosed connections/statements, and returns all carts instead of search results, breaking functionality called from CartController.searchCarts.

Code suggestion
Check the AI-generated fix before applying
Suggested change
public List<Cart> searchCarts(String searchTerm) {
try {
Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
String query = "SELECT * FROM carts c JOIN cart_items ci ON c.id = ci.cart_id WHERE ci.product_name LIKE '%" + searchTerm + "%'";
ResultSet rs = stmt.executeQuery(query);
return cartRepository.findAll();
} catch (Exception e) {
logger.error("Error searching carts", e);
return List.of();
}
}
public List<Cart> searchCarts(String searchTerm) {
try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(
"SELECT DISTINCT c.id FROM carts c JOIN cart_items ci ON c.id = ci.cart_id WHERE ci.product_name LIKE ?")) {
stmt.setString(1, "%" + searchTerm + "%");
ResultSet rs = stmt.executeQuery();
List<Long> cartIds = new ArrayList<>();
while (rs.next()) {
cartIds.add(rs.getLong("id"));
}
return cartRepository.findAllById(cartIds);
} catch (Exception e) {
logger.error("Error searching carts", e);
return List.of();
}
}

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them


@Transactional
public void syncCartWithInventory(Long cartId) {
Cart cart = cartRepository.findById(cartId).get();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix unsafe Optional in getCartTotal

Using .get() on Optional in getCartTotal can throw NoSuchElementException if the cart doesn't exist, affecting any callers of this method.

Code suggestion
Check the AI-generated fix before applying
Suggested change
Cart cart = cartRepository.findById(cartId).get();
Cart cart = cartRepository.findById(cartId)
.orElseThrow(() -> new CartNotFoundException("Cart not found with id: " + cartId));

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Comment on lines +150 to +153
public void removeItemFromCart(Long cartId, Long itemId) {
Cart cart = cartRepository.findById(cartId).get();
cart.getItems().removeIf(item -> item.getId().equals(itemId));
cart.setTotal(calculateTotal(cart));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent Optional handling

Using .get() on Optional can throw NoSuchElementException, inconsistent with other methods that use orElseThrow for specific exceptions. This impacts removeItemFromCart by potentially causing unhandled runtime exceptions instead of meaningful CartNotFoundException. Replace with orElseThrow(() -> new CartNotFoundException("Cart not found: " + cartId)).

Code suggestion
Check the AI-generated fix before applying
Suggested change
public void removeItemFromCart(Long cartId, Long itemId) {
Cart cart = cartRepository.findById(cartId).get();
cart.getItems().removeIf(item -> item.getId().equals(itemId));
cart.setTotal(calculateTotal(cart));
public void removeItemFromCart(Long cartId, Long itemId) {
Cart cart = cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException("Cart not found with id: " + cartId));
cart.getItems().removeIf(item -> item.getId().equals(itemId));
cart.setTotal(calculateTotal(cart));

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Comment on lines +159 to +162
Cart cart = cartRepository.findById(cartId).get();

for (CartItem item : cart.getItems()) {
Product product = productRepository.findById(item.getProductId()).get();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe entity retrieval

Similar to the previous issue, syncCartWithInventory uses .get() for both cart and product lookups, risking NoSuchElementException. This affects inventory sync operations by failing unexpectedly on missing entities. Replace cart lookup with orElseThrow(() -> new CartNotFoundException("Cart not found: " + cartId)) and product lookup with orElseThrow(() -> new ProductNotFoundException("Product not found: " + item.getProductId())).

Code suggestion
Check the AI-generated fix before applying
Suggested change
Cart cart = cartRepository.findById(cartId).get();
for (CartItem item : cart.getItems()) {
Product product = productRepository.findById(item.getProductId()).get();
Cart cart = cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException("Cart not found with id: " + cartId));
for (CartItem item : cart.getItems()) {
Product product = productRepository.findById(item.getProductId()).orElseThrow(() -> new ProductNotFoundException("Product not found with id: " + item.getProductId()));

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

for (CartItem item : cart.getItems()) {
Product product = productRepository.findById(item.getProductId()).get();

if (product.getStock() < item.getQuantity()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect stock reduction condition

The inventory synchronization logic incorrectly reduces stock only when it's insufficient, which can lead to negative stock values. This affects syncCartWithInventory by causing incorrect inventory updates that could disrupt downstream order fulfillment and reporting systems. Change the condition to >= to reduce stock only when sufficient inventory exists.

Code suggestion
Check the AI-generated fix before applying
Suggested change
if (product.getStock() < item.getQuantity()) {
if (product.getStock() >= item.getQuantity()) {

Code Review Run #866f2f


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants